#!/usr/bin/python
# -*- coding: utf-8 -*-
#==Ethersense create an interactive graph of your local network, to overview and play with it.==

#[http://www.labinf.polito.it/~s121407/ethersense.html http://www.labinf.polito.it/~s121407/sshot.png]

#*Ethersense is in a very beta version, i'll be glad to help anybody wont to be betatester.*

#Ethersense passively sniff your connection and create a graphical map of your local network, browsable with a practical web interface.

#To use it simply
#{{{
#svn checkout http://ethersense.googlecode.com/svn/trunk/ ethersense-read-only
#}}}

#Comments, suggestions, code improvement, suggestions, are really appreciated. 

import re

from scapy.all import *
import getopt, os, sys, pwd, grp
from scapy.error import Scapy_Exception
from threading import Thread, Lock
from PktHandler import * 
from XMLHandler import *
import socket
import time
import webbrowser
from subprocess import Popen,PIPE
  
#################################
##### Define some constants #####
#################################
conf.verb=0
conf.promisc=1

usagemsg="""
    EtherSense daemon, Emilio Pinna 2009"
    
    Usage: Ethersense -i interface [options]"
    
      		-i, --interface        : select interface"
    Options:	-h, --help             : display this help"
"""    

################
##### main #####
################

class ethersense:

  def __init__(self):
    self.pkthandler=''
    self.outfile='www/out.xml'
    self.lock=Lock()

  def main(self):

      myiface=conf.iface


      try:
	  opts, args = getopt.getopt(sys.argv[1:], 'hi:', ['help','interface'])
      except getopt.error, msg:
	  print "Error:", msg
	  print usagemsg
	  exit(1)

      ## process options
      for o, a in opts:
	  if o in ('-h', '--help'):
	      print usagemsg
	      exit(1)
	  elif o in ('-i', '--interface'):
	      myiface=a
	  else:
	      print usagemsg
	      exit(1)


      # METTERE SOLO SE IN LINUX
      if os.getuid()!=0:
	print 'Have you enough privileges? Try with \'sudo', ' '.join(sys.argv) + '\''
	exit(1)

      u, g = runAsNormal()
      print '[+] EtherSense started on', myiface, 'with user \'' + pwd.getpwuid(os.geteuid())[0] + '\' privileges'
      

      #######################
      # Object pkthandler #
      #######################
      
      try:  
	self.pkthandler=PktHandler(myiface)
      except IOError, (v, m):
	print 'IOError:', m
	exit(1)



      try:
	self.pkthandler.writeout(self.outfile)
      except IOError, (v, m):
	print 'Error opening', self.outfile + ':', m
	exit(1)

      # Figlio	#
      t_sniff=ThreadSniff(myiface, self.pkthandler,self.outfile,self.lock)
      t_sniff.start()
      t_xml=ThreadXML(self.pkthandler,self.outfile,self.lock)
      t_xml.start()
      
      #	Padre	#      
      time.sleep(2)
      url = 'file://' + os.getcwd() + '/www/ethersense.html'
      print '[!] Opening web interface with firefox in next 7 seconds.\n    If it fails, point a browser to ' + url
      time.sleep(5)
      runExtCmnd('firefox ' + url);

      try:
	while 1:
	  pass
	    #self.lock.acquire()
	    #i=self.pkthandler.garbageCollector()
	    #self.pkthandler.writeout(self.outfile)
	    #self.lock.release()
	    #print '[!]', self.outfile, 'written [-' + str(i) + ']' 
	    #time.sleep(1)
      except (KeyboardInterrupt):
	print '[!] EtherSense quitting..'
	t_sniff.stop()
	t_xml.stop()
	t_sniff.join() 
	t_xml.join()
	
	exit(0)


class ThreadSniff(Thread):
  def __init__(self,myiface,pkthndl,outfile,lock):
      Thread.__init__(self)
      self.myiface=myiface
      self.pkthndl=pkthndl
      self.alive=True
      self.outfile=outfile
      self.lock=lock
  def stop(self):
    self.alive=False
  def run(self):
    try:      
      while 1:
	if self.alive:
	  runAsPrivileged()
	  sniff(iface=self.myiface,prn=self.pkthndl.procPkt, store=0, timeout=5)
	  runAsNormal()
	  #print time.time()
	  self.lock.acquire()
	  self.pkthndl.writeout(self.outfile)
	  self.lock.release()
	  #print time.time()
	else:
	  print '[!] EtherSense sniffer quitted.'
	  exit(0)
    except socket.error, (v,m):
      print 'Socket error:', m
      if 'No such device' in m:
	print 'Unable to open', myiface, 'device.'
      exit(1)
    except IOError, (v, m):
      print 'IOError:', m
      exit(1)
    except (KeyboardInterrupt):
      exit(0)

def getNormalId():
  user="nobody"
  group="nogroup"

  if os.getenv("SUDO_UID") and os.getenv("SUDO_GID"):
    uid=int(os.getenv("SUDO_UID"))
    gid=int(os.getenv("SUDO_GID"))
  else:
    uid = pwd.getpwnam( user )[2]
    gid = grp.getgrnam( group )[2]

  return uid, gid

def runAsNormal():

  uid,gid = getNormalId()
  os.setegid( gid )
  os.seteuid( uid )
  
  return uid, gid
  
def runAsPrivileged():
  uid = pwd.getpwnam( 'root' )[2] #os.geteuid()
  gid = grp.getgrnam( 'root' )[2]
  os.seteuid( uid )
  os.setegid( gid )

def runExtCmnd(command):
  if(os.getenv('SUDO_USER')):
    user = os.getenv('SUDO_USER')
  else:
    user = 'nobody'

  string = 'sudo -u ' + user + ' ' + command
  p = Popen(string, shell=True,stdout=PIPE,stderr=PIPE)


if __name__ == "__main__":
    
    app=ethersense()
    app.main()
    